
package com.sx.core.page;

import org.springframework.core.convert.converter.Converter;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;


/**
 * TODO: DOCUMENT ME!
 *
 * @author   <a href="mailto:lihao@ozstrategy.com">Hao Li</a>
 * @version  03/27/2017 17:06
 */
abstract class Chunk<T> implements Slice<T>, Serializable {
  //~ Static fields/initializers ---------------------------------------------------------------------------------------

  private static final long serialVersionUID = 867755909294344406L;

  //~ Instance fields --------------------------------------------------------------------------------------------------

  private final List<T>  content  = new ArrayList<T>();
  private final Pageable pageable;

  //~ Constructors -----------------------------------------------------------------------------------------------------

  /**
   * Creates a new Chunk object.
   *
   * @param  content   List
   * @param  pageable  Pageable
   */
  public Chunk(List<T> content, Pageable pageable) {
    Assert.notNull(content, "Content must not be null!");

    this.content.addAll(content);
    this.pageable = pageable;
  }

  //~ Methods ----------------------------------------------------------------------------------------------------------

  /**
   * @see  Object#equals(Object)
   */
  @Override public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }

    if (!(obj instanceof Chunk<?>)) {
      return false;
    }

    Chunk<?> that = (Chunk<?>) obj;

    boolean contentEqual  = this.content.equals(that.content);
    boolean pageableEqual = (this.pageable == null) ? (that.pageable == null) : this.pageable.equals(that.pageable);

    return contentEqual && pageableEqual;
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#getContent()
   */
  @Override public List<T> getContent() {
    return Collections.unmodifiableList(content);
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#getNumber()
   */
  @Override public int getNumber() {
    return (pageable == null) ? 0 : pageable.getPageNumber();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#getNumberOfElements()
   */
  @Override public int getNumberOfElements() {
    return content.size();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#getSize()
   */
  @Override public int getSize() {
    return (pageable == null) ? 0 : pageable.getPageSize();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#getSort()
   */
  @Override public Sort getSort() {
    return (pageable == null) ? null : pageable.getSort();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#hasContent()
   */
  @Override public boolean hasContent() {
    return !content.isEmpty();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Object#hashCode()
   */
  @Override public int hashCode() {
    int result = 17;

    result += 31 * ((pageable == null) ? 0 : pageable.hashCode());
    result += 31 * content.hashCode();

    return result;
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#hasPrevious()
   */
  @Override public boolean hasPrevious() {
    return getNumber() > 0;
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#isFirst()
   */
  @Override public boolean isFirst() {
    return !hasPrevious();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#isLast()
   */
  @Override public boolean isLast() {
    return !hasNext();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Iterable#iterator()
   */
  @Override public Iterator<T> iterator() {
    return content.iterator();
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#nextPageable()
   */
  @Override public Pageable nextPageable() {
    return hasNext() ? pageable.next() : null;
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * @see  Slice#previousPageable()
   */
  @Override public Pageable previousPageable() {
    if (hasPrevious()) {
      return pageable.previousOrFirst();
    }

    return null;
  }

  //~ ------------------------------------------------------------------------------------------------------------------

  /**
   * getter method for converted content.
   *
   * @param   <S>        Converter
   * @param   converter  Converter
   *
   * @return  List
   */
  protected <S> List<S> getConvertedContent(Converter<? super T, ? extends S> converter) {
    Assert.notNull(converter, "Converter must not be null!");

    List<S> result = new ArrayList<S>(content.size());

    for (T element : this) {
      result.add(converter.convert(element));
    }

    return result;
  }
} // end class Chunk
